﻿Imports System.Collections.Generic
Imports System.Text
Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Windows.Forms
Imports System.ComponentModel
Imports System.Drawing.Design


''' <summary>
''' Spezielle Progressbar im iTunes Stile mit welcher mehrere Werte angezeigt werden können.
''' </summary>
<ToolboxBitmap(GetType(ProgressBar))> <Description("Eine Timelineprogressbar im Stil eines Filmstreifens")> _
Public Class Filmstripbar
    Inherits Control


#Region "SpecialProgressBarStyle enumeration"
    ''' <summary>
    ''' Lists possible styles
    ''' </summary>
    Public Enum SpecialProgressBarStyle
        Square
        Round
    End Enum
#End Region

#Region "private fields"
    ''' <summary>
    ''' Stil der Progressbar
    ''' </summary>
    Private m_style As SpecialProgressBarStyle = SpecialProgressBarStyle.Square

    ''' <summary>
    ''' Position des Linemarkers
    ''' </summary>
    Private LineMarker As Single = 0

    ''' <summary>
    ''' Linemerker im Vordergrund
    ''' </summary>
    Private LineMarkerOnForeground As Boolean = False

    ''' <summary>
    ''' Stärke des Linemarker
    ''' </summary>
    Private m_LineMarkerThickness As Integer = 4

    ''' <summary>
    ''' Heller Teil der Füllung
    ''' </summary>
    Private m_lightFillColor As Color = Color.Red

    ''' <summary>
    ''' Dunkler Teil der Füllung
    ''' </summary>
    Private m_darkFillColor As Color = Color.DarkRed

    ''' <summary>
    ''' Heller Teil des Hintergrunds
    ''' </summary>
    Private m_lightBackColor As Color = Color.LightGreen

    ''' <summary>
    ''' Dunkler Teil des Hintergrunds
    ''' </summary>
    Private m_darkBackColor As Color = Color.DarkGreen

    ''' <summary>
    ''' Durchsichtigkeit der Values
    ''' </summary>
    Private m_ValueOpacity As Integer = 100

    ''' <summary>
    ''' Farbe des Linemarkers
    ''' </summary>
    Private m_LineMarkerColor As Color = Color.Red

    ''' <summary>
    ''' Füllstartwerte
    ''' </summary>
    Private m_startValue As New List(Of Single)

    ''' <summary>
    ''' Füllendwerte
    ''' </summary>
    Private m_endValue As New List(Of Single)

    ''' <summary>
    ''' Liste der Filmstripbitmaps
    ''' </summary>
    Private m_Filmbitmaps As New List(Of Bitmap)

    ''' <summary>
    ''' Nimmt den String des Auswahldialogs für die Values auf
    ''' </summary>
    Private mPropertyCutValues As String

    ''' <summary>
    ''' Nimmt den String des Auswahldialogs für die Bilder auf
    ''' </summary>
    Private mPropertyFilmImages As New ImageList
#End Region

#Region "public events"

    ''' <summary>
    ''' Fired, when light fill color changed
    ''' </summary>
    Public Event LightFillColorChanged As EventHandler

    ''' <summary>
    ''' Fired, when dark fill color changed
    ''' </summary>
    Public Event DarkFillColorChanged As EventHandler

    ''' <summary>
    ''' Fired, when light background color changed
    ''' </summary>
    Public Event LightBackColorChanged As EventHandler

    ''' <summary>
    ''' Fired, when dark background color changed
    ''' </summary>
    Public Event DarkBackColorChanged As EventHandler

    ''' <summary>
    ''' Fired, when starting value changed
    ''' </summary>
    Public Event StartValueChanged(ByVal sender As Object, ByVal e As ProgressEventArgs)

    ''' <summary>
    ''' Fired, when ending value changed
    ''' </summary>
    Public Event EndValueChanged(ByVal sender As Object, ByVal e As ProgressEventArgs)

    ''' <summary>
    ''' Fired, when change the opacity
    ''' </summary>
    Public Event ValuesOpacityChanged As EventHandler

    ''' <summary>
    ''' Fired, when the linemarker position has changed
    ''' </summary>
    Public Event LinemarkerPositionChanged(ByVal sender As Object, ByVal e As ProgressEventArgs)

    ''' <summary>
    ''' Fired, when changed the LineMarkerthickness or Position
    ''' </summary>
    <Description("Wird gefeuert wenn der Linemarker in irgendeiner Art geändert wird")> _
    Public Event LineMarkerChanged As EventHandler
#End Region

#Region "properties"
    ''' <summary>
    ''' Specifyes the ending's style
    ''' </summary>
    <DefaultValue(GetType(iTunesCutBar.SpecialProgressBarStyle), "Square")> _
    <Category("Werteeinstellung")> _
    <Description("Gibt den Stil der Progressbar an oder gibt diesen zurück")> _
    Public Property Style() As SpecialProgressBarStyle
        Get
            Return Me.m_style
        End Get
        Set(ByVal value As SpecialProgressBarStyle)
            If Me.m_style <> value Then
                Me.m_style = value
                Invalidate()
                OnStyleChanged(EventArgs.Empty)
            End If
        End Set
    End Property


    ''' <summary>
    ''' Specifyes the light fill color of gradient
    ''' </summary>
    <DefaultValue(GetType(Color), "Red")> _
    <Category("Werteeinstellung")> _
    <Description("Gibt den hellen Teil der füllung der Bar an oder gibt diesem zurück")> _
    Public Property LightFillColor() As Color
        Get
            Return Me.m_lightFillColor
        End Get
        Set(ByVal value As Color)
            If Me.m_lightFillColor <> value Then
                Me.m_lightFillColor = value
                Invalidate()
                OnLightFillColorChanged(EventArgs.Empty)
            End If
        End Set
    End Property

    ''' <summary>
    ''' Specifyes the dark fill color of gradient
    ''' </summary>
    <DefaultValue(GetType(Color), "DarkRed")> _
    <Category("Werteeinstellung")> _
    <Description("Gibt den dunklen Teil der Füllfarbe der Bar an oder gibt diesen zurück")> _
    Public Property DarkFillColor() As Color
        Get
            Return Me.m_darkFillColor
        End Get
        Set(ByVal value As Color)
            If Me.m_darkFillColor <> value Then
                Me.m_darkFillColor = value
                Invalidate()
                OnDarkFillColorChanged(EventArgs.Empty)
            End If
        End Set
    End Property

    ''' <summary>
    ''' Specifyes the light background color of gradient
    ''' </summary>
    <DefaultValue(GetType(Color), "LightGreen")> _
    <Category("Werteeinstellung")> _
    <Description("Gibt die Hintegrundfarbe des hellen Teils der Bar an oder gibt diese zurück")> _
    Public Property LightBackColor() As Color
        Get
            Return Me.m_lightBackColor
        End Get
        Set(ByVal value As Color)
            If Me.m_lightBackColor <> value Then
                Me.m_lightBackColor = value
                Invalidate()
                OnLightBackColorChanged(EventArgs.Empty)
            End If
        End Set
    End Property

    ''' <summary>
    ''' Specifyes the dark background color of gradient
    ''' </summary>
    <DefaultValue(GetType(Color), "DarkGreen")> _
    <Category("Werteeinstellung")> _
    <Description("Gibt die Hintergrundfarbe des dunklen Teil der Bar an oder gibt diese zurück")> _
    Public Property DarkBackColor() As Color
        Get
            Return Me.m_darkBackColor
        End Get
        Set(ByVal value As Color)
            If Me.m_darkBackColor <> value Then
                Me.m_darkBackColor = value
                Invalidate()
                OnDarkBackColorChanged(EventArgs.Empty)
            End If
        End Set
    End Property

    ''' <summary>
    ''' Specifyes the Opacity of the Valuesbars
    ''' </summary>
    <DefaultValue(100)> _
    <Description("Bestimmt den grad der Duchsichtigkeit der Valuesbalken oder gibt diesen zurück. Wert muss >0 und >=100 sein.")> _
    <Category("Werteeinstellung")> _
    Public Property ValuesOpacity() As Integer
        Get
            Return m_ValueOpacity
        End Get
        Set(ByVal value As Integer)
            If value > 0 Or value <= 100 Then
                m_ValueOpacity = value
            End If
            Me.Invalidate()
        End Set
    End Property

    ''' <summary>
    ''' Specifyes starting value
    ''' </summary>
    <Category("Werteeinstellung")> _
    <Description("Verlangt ein List(of Single) um die StartCuts oder Terminstarts zu Kennzeichnen oder gibt diese zurück. Die List.Count sollte gleich sein mit der Liste des EndCutValues.Count")> _
    Public Property StartCutValues() As List(Of Single)
        Get
            Return Me.m_startValue
        End Get
        Set(ByVal value As List(Of Single))
            If EndCutValues.Count < value.Count Then
                For o As Integer = value.Count - EndCutValues.Count To value.Count
                    EndCutValues.Add(value(o - 1) + 0.1)
                Next
            End If
            Me.m_startValue = value
            Invalidate()
            OnStartValueChanged(New ProgressEventArgs)
        End Set
    End Property

    ''' <summary>
    ''' The Listof Bitmaps for the Filmstrip
    ''' </summary>
    <Browsable(False)> _
    <Category("Werteeinstellung")> _
    <Description("Verlangt ein List(of Single) um die StartCuts oder Terminstarts zu Kennzeichnen oder gibt diese zurück. Die List.Count sollte gleich sein mit der Liste des EndCutValues.Count")> _
    Public Property Filmbitmaps() As List(Of Bitmap)
        Get
            Return Me.m_Filmbitmaps
        End Get
        Set(ByVal value As List(Of Bitmap))
            Me.m_Filmbitmaps = value
            Invalidate()
        End Set
    End Property

    ''' <summary>
    ''' Specifyes ending value
    ''' </summary>
    <Category("Werteeinstellung")> _
    <Description("Verlangt ein List(of Single) um die EndCuts oder Terminenden zu Kennzeichnen oder gibt diese zurück. Die List.Count sollte gleich sein mit der Liste des StartCutValues.Count")> _
   Public Property EndCutValues() As List(Of Single)
        Get
            Return Me.m_endValue
        End Get
        Set(ByVal value As List(Of Single))
            If StartCutValues.Count < value.Count Then
                For o1 As Integer = value.Count - StartCutValues.Count To value.Count
                    StartCutValues.Add(value(o1 - 1) - 0.1)
                Next
            End If
            Me.m_endValue = value
            Invalidate()
            OnEndValueChanged(New ProgressEventArgs)
        End Set
    End Property
    ''' <summary>
    ''' Postion of the LineMarker
    ''' </summary>
    <DefaultValue(0)> _
    <Category("Werteeinstellung")> _
    <Description("Gibt an wo sich der Marker befinden soll oder gibt den Wert der aktuellen Positione zurück")> _
   Public Property LineMarkerPosition() As Single
        Get
            Return LineMarker
        End Get
        Set(ByVal value As Single)
            If value < 0 Then
                value = 0
            End If
            If value > 100 Then
                value = 100
            End If
            LineMarker = value
            Invalidate()
            OnLineMarkerPositionChanged(New ProgressEventArgs)
        End Set
    End Property

    ''' <summary>
    ''' Gets or sets the LineMarker to foreground
    ''' </summary>
    <DefaultValue(False)> _
    <Category("Werteeinstellung")> _
    <Description("Gibt an ob sich der Linemarker vor oder hinter den Filmstreifen befinden soll")> _
   Public Property LineMarkerForeground() As Boolean
        Get
            Return LineMarkerOnForeground
        End Get
        Set(ByVal value As Boolean)
            LineMarkerOnForeground = value
            Invalidate()
            OnLineMarkerChanged(EventArgs.Empty)
        End Set
    End Property

    ''' <summary>
    ''' Thickness of the Linemarker
    ''' </summary>
    <DefaultValue(4)> _
    <Category("Werteeinstellung")> _
    <Description("Gibt die Linienstärke des Markers an oder gibt diese zurück")> _
    Public Property LineMarkerThickness() As Integer
        Get
            Return Me.m_LineMarkerThickness
        End Get
        Set(ByVal value As Integer)
            If Me.m_LineMarkerThickness <> value Then
                If value > 10 Or value < 1 Then
                    Throw New Exception("Wert muss zwischen 1 und 10 liegen")
                Else
                    Me.m_LineMarkerThickness = value
                    Invalidate()
                    OnLineMarkerChanged(EventArgs.Empty)
                End If
            End If
        End Set
    End Property

    ''' <summary>
    ''' Specifyes the color of the linemarker
    ''' </summary>
    <DefaultValue(GetType(Color), "Red")> _
    <Category("Werteeinstellung")> _
    <Description("Gibt die Farbe des Linemarkers an oder gibt diese zurück")> _
    Public Property LineMakerColor() As Color
        Get
            Return Me.m_LineMarkerColor
        End Get
        Set(ByVal value As Color)
            If Me.m_LineMarkerColor <> value Then
                Me.m_LineMarkerColor = value
                Invalidate()
                OnLineMarkerChanged(EventArgs.Empty)
            End If
        End Set
    End Property

    ''' <summary>
    ''' The Values of the Bar
    ''' </summary>
    <DefaultValue("")> _
    <Description("Gibt die Start und EndValues für die Bar an. Hier allerdings mit einem angenehmen Editor welcher den umgang vereinfacht und wodurch weniger fehler passieren können.")> _
    <Editor(GetType(CProgressValueProperty), GetType(UITypeEditor))> _
    <Category("Werteeinstellung")> _
    Public Property CutValues() As String
        ' Property für den Wert.
        Get
            mPropertyCutValues = ""
            For i As Integer = 0 To StartCutValues.Count - 1
                mPropertyCutValues += StartCutValues(i) & ";"
                mPropertyCutValues += EndCutValues(i) & ";"
            Next
            If Strings.Left(mPropertyCutValues, 1) = ";" Then
                mPropertyCutValues = Mid(mPropertyCutValues, 1, mPropertyCutValues.Length - 1)
            End If
            Return mPropertyCutValues
        End Get
        Set(ByVal value As String)
            mPropertyCutValues = value
            StartCutValues.Clear()
            EndCutValues.Clear()
            Dim VM As String() = mPropertyCutValues.Split(";")
            For i As Integer = 0 To VM.Count - 1
                If VM(i).Length > 0 Then
                    If i Mod 2 = 0 Then
                        Me.StartCutValues.Add(VM(i))
                    Else
                        Me.EndCutValues.Add(VM(i))
                    End If
                End If
            Next
            OnStartValueChanged(New ProgressEventArgs)
            OnEndValueChanged(New ProgressEventArgs)
            Me.Invalidate()
        End Set
    End Property

    ''' <summary>
    ''' The Imagelist of the bar
    ''' </summary>
    <DefaultValue("")> _
    <Description("Gibt die Imagelist für die Bilder an welche in der Bar erscheinen sollen. Note: Beim hinzufügen einer Imagelist werden die Bilder Automatisch dem Property 'Filmbitmaps' hinzugefügt")> _
    <Category("Werteeinstellung")> _
    Public Property FilmImages() As ImageList
        Get
            Return mPropertyFilmImages
        End Get
        Set(ByVal value As ImageList)
            For Each itm As Image In value.Images
                Me.Filmbitmaps.Add(itm)
            Next
            mPropertyFilmImages = value
        End Set
    End Property
#End Region

#Region "Constructor"
    ''' <summary>
    ''' Constructor
    ''' </summary>
    Public Sub New()
        MyBase.New()
        Size = New Size(320, 32)
        DoubleBuffered = True

    End Sub

    ''' <summary>
    ''' Constructor
    ''' </summary>
    ''' <param name="text__1">Text member</param>
    Public Sub New(ByVal text__1 As String)
        MyBase.New(text__1)
        Size = New Size(320, 32)
        DoubleBuffered = True

    End Sub

    ''' <summary>
    ''' Constructor
    ''' </summary>
    ''' <param name="parent">Parent control</param>
    ''' <param name="text__1">Text members</param>
    Public Sub New(ByVal parent As Control, ByVal text__1 As String)
        MyBase.New(parent, text__1)
        Size = New Size(320, 32)
        DoubleBuffered = True

    End Sub

    ''' <summary>
    ''' Constructor
    ''' </summary>
    ''' <param name="text__1">Text member</param>
    ''' <param name="left">X-coordinate</param>
    ''' <param name="top">Y-coordinate</param>
    ''' <param name="width">Width member</param>
    ''' <param name="height">Height member</param>
    Public Sub New(ByVal text__1 As String, ByVal left As Integer, ByVal top As Integer, ByVal width As Integer, ByVal height As Integer)
        MyBase.New(text__1, left, top, width, height)
        DoubleBuffered = True

    End Sub

    ''' <summary>
    ''' Constructor
    ''' </summary>
    ''' <param name="parent">Parent control</param>
    ''' <param name="text__1">Text member</param>
    ''' <param name="left">X-coordinate</param>
    ''' <param name="top">Y-coordinate</param>
    ''' <param name="width">Width member</param>
    ''' <param name="height">Height member</param>
    Public Sub New(ByVal parent As Control, ByVal text__1 As String, ByVal left As Integer, ByVal top As Integer, ByVal width As Integer, ByVal height As Integer)
        MyBase.New(parent, text__1, left, top, width, height)
        DoubleBuffered = True

    End Sub
#End Region

#Region "protected members"

    ''' <summary>
    ''' Fired, when light fill color changed
    ''' </summary>
    Protected Sub OnLightFillColorChanged(ByVal e As EventArgs)
        RaiseEvent LightFillColorChanged(Me, e)
    End Sub

    ''' <summary>
    ''' Fired, when dark fill color changed
    ''' </summary>
    Protected Sub OnDarkFillColorChanged(ByVal e As EventArgs)
        RaiseEvent DarkFillColorChanged(Me, e)
    End Sub

    ''' <summary>
    ''' Fired, when light background color changed
    ''' </summary>
    Protected Sub OnLightBackColorChanged(ByVal e As EventArgs)
        RaiseEvent LightBackColorChanged(Me, e)
    End Sub

    ''' <summary>
    ''' Fired, when dark background color changed
    ''' </summary>
    Protected Sub OnDarkBackColorChanged(ByVal e As EventArgs)
        RaiseEvent DarkBackColorChanged(Me, e)
    End Sub

    ''' <summary>
    ''' Fired, when starting value changed
    ''' </summary>
    Protected Sub OnStartValueChanged(ByVal e As ProgressEventArgs)
        e.StartValues = Me.StartCutValues
        e.EndValues = Me.EndCutValues
        e.Linemarkerposition = Me.LineMarkerPosition
        RaiseEvent StartValueChanged(Me, e)
    End Sub

    ''' <summary>
    ''' Fired, when ending value changed
    ''' </summary>
    Protected Sub OnEndValueChanged(ByVal e As ProgressEventArgs)
        e.StartValues = Me.StartCutValues
        e.EndValues = Me.EndCutValues
        e.Linemarkerposition = Me.LineMarkerPosition
        RaiseEvent EndValueChanged(Me, e)
    End Sub

    ''' <summary>
    ''' Fired, when ending value changed
    ''' </summary>
    Protected Sub OnLineMarkerChanged(ByVal e As EventArgs)
        RaiseEvent LineMarkerChanged(Me, e)
    End Sub

    ''' <summary>
    ''' Fired, when ending value changed
    ''' </summary>
    Protected Sub OnLineMarkerPositionChanged(ByVal e As ProgressEventArgs)
        e.StartValues = Me.StartCutValues
        e.EndValues = Me.EndCutValues
        e.Linemarkerposition = Me.LineMarkerPosition
        RaiseEvent LinemarkerPositionChanged(Me, e)
    End Sub

    ''' <summary>
    ''' Fired when Resized
    ''' </summary>
    Protected Overrides Sub OnResize(ByVal e As System.EventArgs)
        Me.Invalidate()
        MyBase.OnResize(e)
    End Sub

    ''' <summary>
    ''' Fired, when size changed
    ''' </summary>
    Protected Overrides Sub OnSizeChanged(ByVal e As EventArgs)
        If Height > Width Then
            Width = Height
        End If

        MyBase.OnSizeChanged(e)
    End Sub

    ''' <summary>
    ''' Fired, when text changed
    ''' </summary>
    Protected Overrides Sub OnTextChanged(ByVal e As EventArgs)
        Invalidate()
        MyBase.OnTextChanged(e)
    End Sub

    ''' <summary>
    ''' Fired on paint event
    ''' </summary>
    Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
        Dim rect As New Rectangle(1, 1, Width - 2, Height - 2)
        Dim g As Graphics = e.Graphics
        g.SmoothingMode = SmoothingMode.HighQuality

        Dim path As GraphicsPath = GetPath(rect)

        ' Draw back gradient
        Using brush As New LinearGradientBrush(rect, LightBackColor, DarkBackColor, LinearGradientMode.Vertical)
            g.FillPath(brush, path)
        End Using
        'Draw Linemarker if Linemarkerforeground = False
        If LineMarkerForeground = False Then
            If LineMarkerPosition >= 0 Then
                Using pen1 As New Pen(LineMakerColor, LineMarkerThickness)
                    g.SetClip(path)
                    Dim proz As Single = (rect.Width / 100) * LineMarkerPosition

                    g.DrawLine(pen1, proz - 0.5F, rect.Y - 0.5F, proz, rect.Y + rect.Height - 0.5F)
                    'Oberes Dreieck
                    Dim l As New List(Of Point)
                    l.Add(New Point(proz - 4.0F - LineMarkerThickness, rect.Y - 0.5F))
                    l.Add(New Point(proz + 4.0F + LineMarkerThickness, rect.Y - 0.5F))
                    l.Add(New Point(proz, rect.Y + 4.0F + LineMarkerThickness))
                    Dim br As Brush = pen1.Brush
                    g.FillPolygon(br, l.ToArray)
                    g.ResetClip()

                    'Unteres Dreieck
                    g.SetClip(path)
                    Dim l1 As New List(Of Point)
                    l1.Add(New Point(proz - 4.0F - LineMarkerThickness, (rect.Y + rect.Height) + 0.5F))
                    l1.Add(New Point(proz + 4.0F + LineMarkerThickness, (rect.Y + rect.Height) + 0.5F))
                    l1.Add(New Point(proz, rect.Y + rect.Height - 4.0F - LineMarkerThickness))
                    g.FillPolygon(br, l1.ToArray)
                    g.ResetClip()
                End Using
            End If
        End If

        'Draw the Filmstrip Bitmap ------------
        g.SetClip(path)
        Dim Gesamtbreite As Integer = 0
        Dim Counter As Integer = 0
        Dim bTemp As Bitmap = My.Resources.negativ
        bTemp = PicResizeByHeight(bTemp, rect.Height)
        Do
            Using myimg As New Bitmap(bTemp)
                If Filmbitmaps.Count > 0 Then
                    If Filmbitmaps.Count - 1 >= Counter Then

                        Dim bFilm As New Bitmap(PicResize(Filmbitmaps(Counter), rect.Height - 22, bTemp.Width))
                        If bFilm IsNot Nothing Then
                            g.DrawImage(bFilm, New PointF(Gesamtbreite + rect.X, rect.Y + 11))
                        End If
                    End If
                End If
                g.DrawImage(myimg, New PointF(Gesamtbreite + rect.X, rect.Y))
                Gesamtbreite += bTemp.Width - 1 : Counter += 1

            End Using
        Loop Until (Gesamtbreite >= rect.Width)
        bTemp = Nothing
        g.ResetClip()
        '-------------------------------------

        'Draw Linemarker if Linemarkerforeground = true
        If LineMarkerForeground = True Then
            If LineMarkerPosition >= 0 Then
                Using pen1 As New Pen(LineMakerColor, LineMarkerThickness)
                    g.SetClip(path)
                    Dim proz As Single = (rect.Width / 100) * LineMarkerPosition

                    g.DrawLine(pen1, proz - 0.5F, rect.Y - 0.5F, proz, rect.Y + rect.Height - 0.5F)
                    'Oberes Dreieck
                    Dim l As New List(Of Point)
                    l.Add(New Point(proz - 4.0F - LineMarkerThickness, rect.Y - 0.5F))
                    l.Add(New Point(proz + 4.0F + LineMarkerThickness, rect.Y - 0.5F))
                    l.Add(New Point(proz, rect.Y + 4.0F + LineMarkerThickness))
                    Dim br As Brush = pen1.Brush
                    g.FillPolygon(br, l.ToArray)
                    g.ResetClip()

                    'Unteres Dreieck
                    g.SetClip(path)
                    Dim l1 As New List(Of Point)
                    l1.Add(New Point(proz - 4.0F - LineMarkerThickness, (rect.Y + rect.Height) + 0.5F))
                    l1.Add(New Point(proz + 4.0F + LineMarkerThickness, (rect.Y + rect.Height) + 0.5F))
                    l1.Add(New Point(proz, rect.Y + rect.Height - 4.0F - LineMarkerThickness))
                    g.FillPolygon(br, l1.ToArray)
                    g.ResetClip()
                End Using
            End If
        End If


        'Check if Startcutvalue.count or Endcutvalue.count is invalid 
        For i As Integer = 0 To StartCutValues.Count - 1
            If EndCutValues.Count < StartCutValues.Count Then
                For o As Integer = StartCutValues.Count - EndCutValues.Count To StartCutValues.Count
                    EndCutValues.Add(StartCutValues(o - 1) + 0.1)
                Next
            End If
            If StartCutValues.Count < EndCutValues.Count Then
                For o1 As Integer = EndCutValues.Count - StartCutValues.Count To EndCutValues.Count
                    StartCutValues.Add(EndCutValues(o1 - 1) - 0.1)
                Next
            End If

            'Draw Cutter
            If EndCutValues(i) - StartCutValues(i) <> 0 Then
                ' Draw fill gradient
                Dim c As Color = Color.FromArgb(50, LightFillColor)
                Using brush As New LinearGradientBrush(rect, Color.FromArgb((Me.ValuesOpacity / 100) * 255, LightFillColor), Color.FromArgb((Me.ValuesOpacity / 100) * 255, DarkFillColor), LinearGradientMode.Vertical)
                    Dim clip As New RectangleF(rect.X + CSng(rect.Width) * CSng(StartCutValues(i)) / 100.0F, rect.Y, CSng(rect.Width) * CSng(EndCutValues(i) - StartCutValues(i)) / 100.0F, rect.Height)

                    g.SetClip(clip)
                    g.FillPath(brush, path)
                    g.ResetClip()
                End Using
            End If
        Next

        ' draw light
        Using brush As New SolidBrush(Color.FromArgb(48, Color.White))
            g.SetClip(path)
            g.FillRectangle(brush, New RectangleF(rect.X, rect.Y, rect.Width, rect.Height / 2.0F))
            g.ResetClip()
        End Using


        'Draw Text
        If Text.Length > 0 Then
            Dim fontSize As SizeF = g.MeasureString(Text, Font)
            Dim fontRect As New RectangleF(rect.X + rect.Width / 2.0F - fontSize.Width / 2.0F, rect.Y + rect.Height / 2.0F - fontSize.Height / 2.0F, fontSize.Width, fontSize.Height)
            g.DrawString(Text, Font, New SolidBrush(ForeColor), fontRect)
        End If

        MyBase.OnPaint(e)
    End Sub
#End Region

#Region "private members"
    Private Function GetPath(ByVal rect As RectangleF) As GraphicsPath
        Dim path As New GraphicsPath()
        Select Case Style
            Case SpecialProgressBarStyle.Square
                path.AddRectangle(rect)
                Exit Select
            Case SpecialProgressBarStyle.Round
                path.AddArc(New RectangleF(rect.X, rect.Y, rect.Height, rect.Height), 90, 180)
                path.AddArc(New RectangleF(rect.X + rect.Width - rect.Height, rect.Y, rect.Height, rect.Height), 270, 180)
                path.CloseFigure()
                Exit Select


        End Select

        Return path
    End Function
#End Region


#Region "public functions"
    ''' <summary>
    ''' Fügt einen neuen Bereich der Bar hinzu feuert die Events und zeichnet das Control anschliessend neu
    ''' Startwert sollte kleiner sein als der Endwert
    ''' </summary>
    ''' <param name="StartValue">Der Startwert des neuen Bereichs</param>
    ''' <param name="EndValue">Der Endwert des neuen Bereichs</param>
    Public Sub AddValues(ByVal StartValue As Single, ByVal EndValue As Single)
        Me.StartCutValues.Add(StartValue)
        OnStartValueChanged(EventArgs.Empty)
        Me.EndCutValues.Add(EndValue)
        OnEndValueChanged(EventArgs.Empty)
        Invalidate()
    End Sub
#End Region

#Region "private functions"
    ''' <summary>
    ''' Diese Funktion ändert die größe eines Bilds und gibt es als Bitmap zurück. Hier ist die neue Höhe veränderbar
    ''' </summary>
    ''' <param name="SourceImage">Das Bild dessen größe verändert werden soll</param>
    ''' <param name="NewHeight">Die neue Breite des Bilds, das Größenverhältnis des Bilds wird eingehalten</param>
    Private Function PicResizeByHeight(ByVal SourceImage As Image, ByVal NewHeight As Integer) As Bitmap
        Dim SizeFactor As Decimal = NewHeight / SourceImage.Height
        Dim NewWidth As Integer = SizeFactor * SourceImage.Width
        Dim NewImage As New Bitmap(NewWidth, NewHeight)
        Using G As Graphics = Graphics.FromImage(NewImage)
            G.InterpolationMode = InterpolationMode.HighQualityBicubic
            G.DrawImage(SourceImage, New Rectangle(0, 0, NewWidth, NewHeight))
        End Using
        Return NewImage
    End Function
    ''' <summary>
    ''' Diese Funktion ändert die größe eines Bilds und gibt es als Bitmap zurück. Hier ist die neue Breite und die neue Höhe veränderbar
    ''' </summary>
    Private Function PicResize(ByVal SourceImage As Image, ByVal NewHeight As Integer, ByVal NewWidth As Integer) As Bitmap
        Dim NewImage As New Bitmap(NewWidth, NewHeight)
        Try
            Using G As Graphics = Graphics.FromImage(NewImage)
                G.InterpolationMode = InterpolationMode.HighQualityBicubic
                G.DrawImage(SourceImage, New Rectangle(0, 0, NewWidth, NewHeight))
            End Using
            Return NewImage
        Catch ex As Exception
            Return NewImage
        End Try
    End Function
#End Region


End Class




